﻿/**
 * 
 * Copyright 2009, 2010 Mike Jamer [email: mikejamer@gmail.com ]
 * 
 * This File is part of Moose IRC
 * 
 * MooseIRC is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * MooseIRC is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with MooseIRC.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;

namespace MooseIRC.Client.Status
{
    /// <summary>
    /// Moose IRC Server Status Window
    /// </summary>
    public partial class StatusForm 
        : Form
    {

        #region [Local Attributes]

        /// <summary>
        /// Socket to MooseIRC Client Server
        /// </summary>
        private Socket m_socket;

        /// <summary>
        /// Recieve Buffer
        /// </summary>
        private StringBuilder m_recieve_buffer;

        #endregion

        #region [Construction]

        /// <summary>
        /// Initialize Status Form
        /// </summary>
        public StatusForm()
            : base()
        {
            Control.CheckForIllegalCrossThreadCalls = false;
            InitializeComponent();
            connect_to_server(int.Parse(
                Environment.CommandLine.Substring(
                    Environment.CommandLine.Trim().LastIndexOf(' ')
                    )
                ));
            return;
        }

        #endregion

        #region [Helper Methods]

        /// <summary>
        /// Echo text to output
        /// </summary>
        /// <param name="message">message to write</param>
        private void echo(string message)
        {
            txtOutput.Text = txtOutput.Text + message + Environment.NewLine;
            txtOutput.Select(txtOutput.Text.Length, 1);
            txtOutput.ScrollToCaret();
            txtInput.Focus();            
            return;
        }

        /// <summary>
        /// Connect us to the server
        /// </summary>
        /// <param name="port"></param>
        private void connect_to_server(int port)
        {
            m_recieve_buffer = new StringBuilder();
            m_socket = create_socket();
            m_socket.Connect("127.0.0.1", port);

            recieve();

            return;
        }

        /// <summary>
        /// Create new socket
        /// </summary>
        /// <returns></returns>
        static Socket create_socket()
        {
            return new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }

        /// <summary>
        /// Send data to client
        /// </summary>
        /// <param name="data"></param>
        private void send(string data)
        {
            byte[] buffer = Encoding.UTF8.GetBytes(data + "\r\n");
            m_socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, onSendComplete, buffer);
        }

        /// <summary>
        /// Sets up recieve from server
        /// </summary>
        private void recieve()
        {
            byte[] buffer = new byte[512];
            m_socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, onRecieveComplete, buffer);
        }

        /// <summary>
        /// Processes Recieve Buffer
        /// </summary>
        /// <returns>Array of all messages that have been completely recieved</returns>
        private string[] processRecieveBuffer()
        {
            List<string> responses = new List<string>();
            while (m_recieve_buffer.ToString().IndexOf("\r\n") != -1)
            {
                string buf = m_recieve_buffer.ToString();
                responses.Add(buf.Substring(0, buf.IndexOf("\r\n")));
                m_recieve_buffer.Remove(0,
                    buf.Substring(0, buf.IndexOf("\r\n")
                    ).Length + 2); //Remove message, plus the CRLF pair
            }
            return responses.ToArray();
        }

        #endregion

        #region [Async. Socket Callbacks]

        /// <summary>
        /// Fires when transmission completes
        /// </summary>
        /// <param name="result">Async. Result</param>
        private void onSendComplete(IAsyncResult result)
        {
            byte[] buffer = (byte[])result.AsyncState;
            int sent = m_socket.EndSend(result);
            if (sent != buffer.Length)
            {
                Console.WriteLine(">>>Transmission to server failed");
            }
            return;
        }

        /// <summary>
        /// Fires when we recieve a new transmission from the server
        /// </summary>
        /// <param name="result">Async. Result</param>
        private void onRecieveComplete(IAsyncResult result)
        {
            byte[] buffer = (byte[])result.AsyncState;
            int recv = m_socket.EndReceive(result);
            m_recieve_buffer.Append(
                Encoding.UTF8.GetString(buffer, 0, recv));

            foreach (string line in processRecieveBuffer())
            {
                echo(line);
            }

            recieve();
            return;
        }

        #endregion
        
        #region [Form Events]

        /// <summary>
        /// Fires when key is pressed in input box
        /// </summary>
        private void txtInput_KeyPress(object sender, KeyPressEventArgs e)
        {
            if (e.KeyChar == '\r')
            {
                send(txtInput.Text);
                txtInput.Clear();
                e.Handled = true;
            }


            return;
        }

        #endregion


    }
}
